home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / C / Games / Xconq 7.1.0 / src / xconq-7.1.0 / kernel / combat.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-07-07  |  49.0 KB  |  1,667 lines  |  [TEXT/R*ch]

  1. /* The combat-related actions of Xconq.
  2.    Copyright (C) 1987, 1988, 1989, 1991, 1992, 1993, 1994, 1995
  3.    Stanley T. Shebs.
  4.  
  5. Xconq is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2, or (at your option)
  8. any later version.  See the file COPYING.  */
  9.  
  10. /* Rules of combat: the attacker hits the defender ("other") unit and its
  11.    occupants, but the damage does not take effect right away.  If counter
  12.    attacks are possible in this period, the defender always does so, with
  13.    the same odds.  If the defender dies, then the attacker moves into the
  14.    cell.  If the attacker dies, nothing happens.  If both survive, then the
  15.    attacker may attempt to capture the defender. */
  16.  
  17. #include "conq.h"
  18. extern int damaged_terrain_type PARAMS ((int t));
  19.  
  20. static int one_attack PARAMS ((Unit *atker, Unit *defender));
  21. static void fire_on_unit PARAMS ((Unit *atker, Unit *other));
  22. static void attack_unit PARAMS ((Unit *atker, Unit *other));
  23. static void maybe_hit_unit PARAMS ((Unit *atker, Unit *other, int fire, int fallsoff));
  24. static void hit_unit PARAMS ((Unit *unit, int hit, Unit *atker));
  25.  
  26. static void reckon_damage_here PARAMS ((int x, int y));
  27. static void report_damage PARAMS ((Unit *unit, Unit *atker, Unit *mainunit));
  28. static int retreat_unit PARAMS ((Unit *unit, Unit *atker));
  29. static int retreat_in_dir PARAMS ((Unit *unit, int dir));
  30. static void attempt_to_capture_unit PARAMS ((Unit *atker, Unit *other));
  31. static void capture_unit_2 PARAMS ((Unit *unit, Unit *pris,
  32.                     Side *prevside));
  33. static void capture_occupant PARAMS ((Unit *unit, Unit *pris, Unit *occ, Side *newside));
  34. static void detonate_on_cell PARAMS ((int x, int y));
  35. static void notify_combat PARAMS ((Unit *unit, Unit *atker, char *str));
  36.  
  37. #undef  DEF_ACTION
  38. #define DEF_ACTION(name,code,args,prepfn,DOFN,checkfn,ARGDECL,doc)  \
  39.   extern int DOFN PARAMS (ARGDECL);
  40.  
  41. #include "action.def"
  42.  
  43. int max_u_detonate_effect_range = -1;
  44.  
  45. int max_t_detonate_effect_range = -1;
  46.  
  47. int max_detonate_on_approach_range = -1;
  48.  
  49. /* Remember what the main units involved are, so display is handled relative
  50.    to them and not to any occupants. */
  51.  
  52. static Unit *amain, *omain;
  53.  
  54.  
  55. int numsoundplays;
  56.  
  57. /* Attack action. */
  58.  
  59. /* This is an attack on a given unit at a given level of commitment. */
  60.  
  61. int
  62. prep_attack_action(unit, unit2, defender, n)
  63. Unit *unit, *unit2, *defender;
  64. int n;
  65. {
  66.     if (unit == NULL || unit->act == NULL)
  67.       return FALSE;
  68.     if (unit2 == NULL)
  69.       return FALSE;
  70.     unit->act->nextaction.type = ACTION_ATTACK;
  71.     unit->act->nextaction.args[0] = defender->id;
  72.     unit->act->nextaction.args[1] = n;
  73.     unit->act->nextaction.actee = unit2->id;
  74.     return TRUE;
  75. }
  76.  
  77. int
  78. do_attack_action(unit, unit2, defender, n)
  79. Unit *unit, *unit2, *defender;
  80. int n;
  81. {
  82.     int u2 = unit2->type, u3 = defender->type;
  83.     int withdrawchance, surrenderchance;
  84.  
  85.     action_point(unit2->side, defender->x, defender->y);
  86.     action_point(defender->side, defender->x, defender->y);
  87.     /* Defender might be a type that can sneak away to avoid attack. */
  88.     withdrawchance = uu_withdraw_per_attack(u2, u3);
  89.     if (withdrawchance > 0) {
  90.     if (probability(withdrawchance)) {
  91.         if (retreat_unit(defender, unit2)) {
  92.             if (alive(unit))
  93.               use_up_acp(unit, uu_acp_to_attack(u2, u3));
  94.         return A_ANY_DONE;
  95.         }
  96.     }
  97.     }
  98.     /* Defender might instead choose to surrender right off. */
  99.     surrenderchance = uu_surrender_per_attack(u2, u3);
  100.     if (surrenderchance > 0) {
  101.     if (probability(surrenderchance)) {
  102.         capture_unit(unit2, defender);
  103.         if (alive(unit))
  104.           use_up_acp(unit, uu_acp_to_attack(u2, u3));
  105.         return A_ANY_DONE;
  106.     }
  107.     }
  108.     /* Carry out a normal attack. */
  109.     one_attack(unit, defender);
  110.     if (alive(unit))
  111.       use_up_acp(unit, uu_acp_to_attack(u2, u3));
  112.     /* The defender in an attack has to take time to defend itself. */
  113.     if (alive(defender)) 
  114.       use_up_acp(defender, uu_acp_to_defend(u2, u3));
  115.     return A_ANY_DONE;
  116. }
  117.  
  118. int
  119. check_attack_action(unit, unit2, defender, n)
  120. Unit *unit, *unit2, *defender;
  121. int n;
  122. {
  123.     int u, u2, u3, acp, u2x, u2y, dfx, dfy, dist, m;
  124.  
  125.     if (!in_play(unit))
  126.       return A_ANY_ERROR;
  127.     if (!in_play(unit2))
  128.       return A_ANY_ERROR;
  129.     if (!in_play(defender))
  130.       return A_ANY_ERROR;
  131.     /* We can't attack ourselves. */
  132.     if (unit2 == defender)
  133.       return A_ANY_ERROR;
  134.     if (unit2->side != NULL && unit2->side == defender->side)
  135.       return A_ANY_ERROR;
  136.     u = unit->type;
  137.     u2 = unit2->type;
  138.     u3 = defender->type;
  139.     acp = uu_acp_to_attack(u2, u3);
  140.     if (acp < 1)
  141.       return A_ANY_CANNOT_DO;
  142.     if (!has_enough_acp(unit, acp))
  143.       return A_ANY_NO_ACP;
  144.     /* Check whether we can attack from inside a transport. */
  145.     if (unit2->transport && uu_occ_combat(u2, unit2->transport->type) == 0)
  146.       return A_ANY_ERROR;
  147.     u2x = unit2->x;  u2y = unit2->y;
  148.     dfx = defender->x;  dfy = defender->y;
  149.     dist = distance(u2x, u2y, dfx, dfy);
  150.     if (dist < uu_attack_range_min(u2, u3))
  151.       return A_ANY_TOO_NEAR;
  152.     if (dist > uu_attack_range(u2, u3))
  153.       return A_ANY_TOO_FAR;
  154.     if (uu_hit(u2, u3) <= 0)
  155.       return A_ANY_ERROR;
  156.     /* We have to have a minimum level of supply to be able to attack. */
  157.     for_all_material_types(m) {
  158.     if (unit2->supply[m] < um_to_fight(u2, m))
  159.       return A_ANY_NO_MATERIAL;
  160.     }
  161.     /* (should prorate ammo needs by intensity of attack) */
  162.     if (!enough_ammo(unit2, defender))
  163.       return A_ANY_ERROR;
  164.     /* Allow attacks even if zero damage, this amounts to "harassment". */
  165.     return A_ANY_OK;
  166. }
  167.  
  168. /* Overrun action. */
  169.  
  170. /* Overrun is an attempt to occupy a given cell that may include attempts
  171.    to attack and/or capture any units in the way. */
  172.  
  173. int
  174. prep_overrun_action(unit, unit2, x, y, z, n)
  175. Unit *unit, *unit2;
  176. int x, y, z, n;
  177. {
  178.     if (unit == NULL || unit->act == NULL)
  179.       return FALSE;
  180.     if (unit2 == NULL)
  181.       return FALSE;
  182.     unit->act->nextaction.type = ACTION_OVERRUN;
  183.     unit->act->nextaction.args[0] = x;
  184.     unit->act->nextaction.args[1] = y;
  185.     unit->act->nextaction.args[2] = z;
  186.     unit->act->nextaction.args[3] = n;
  187.     unit->act->nextaction.actee = unit2->id;
  188.     return TRUE;
  189. }
  190.  
  191. int
  192. do_overrun_action(unit, unit2, x, y, z, n)
  193. Unit *unit, *unit2;
  194. int x, y, z, n;
  195. {
  196.     int u, u2, u3, acpused, mpcost, acpcost, speed, ox, oy, oz;
  197.     Unit *defender;
  198.  
  199.     u = unit->type;  u2 = unit2->type;
  200.     ox = unit2->x;  oy = unit2->y;  oz = unit2->z;
  201.     action_point(unit2->side, x, y);
  202.     acpused = 0;
  203.     /* Attack every defender in turn. */
  204.     for_all_stack(x, y, defender) {
  205.     u3 = defender->type;
  206.     /* Don't attack any of our buddies. */
  207.     if (unit_trusts_unit(unit2, defender))
  208.       continue;
  209.     action_point(defender->side, x, y);
  210.     one_attack(unit2, defender);
  211.     if (alive(unit))
  212.       use_up_acp(unit, uu_acp_to_attack(u2, u3));
  213.     acpused += uu_acp_to_attack(u2, u3);
  214.     /* The target of an attack has to take time to defend itself. */
  215.     if (alive(defender)) {
  216.         use_up_acp(defender, uu_acp_to_defend(u, u3));
  217.     }
  218.     }
  219.     if (!alive(unit2))
  220.       return A_OVERRUN_FAILED;
  221.     if (in_blocking_zoc(unit2, x, y, z))
  222.       return A_OVERRUN_FAILED;
  223.     /* Try to enter the cleared cell now - might still have
  224.        friendlies filling it up already, so check first. */
  225.     if (can_occupy_cell(unit2, x, y)) {
  226.     mpcost = move_unit(unit2, x, y);
  227.     /* Note that we'll say the action succeeded even if
  228.        the cell did not have enough room for us to actually
  229.        be in it, which is a little weird. */
  230.     /* Now add up any extra movement costs of entering the new cell. */
  231.     mpcost += zoc_move_cost(unit2, ox, oy, oz);
  232.     acpcost = 0;
  233.     speed = unit_speed(unit2, x, y);
  234.         if (speed > 0)
  235.       acpcost = (mpcost * 100) / speed;
  236.     acpcost -= acpused;
  237.     if (acpcost > 0) {
  238.         /* Take the movement cost out of the moving unit if possible. */
  239.         use_up_acp(unit2, acpcost);
  240.     }
  241.     /* Count the unit as having actually moved. */
  242.     if (unit2->act)
  243.       ++(unit2->act->actualmoves);
  244.     }
  245.     return A_OVERRUN_SUCCEEDED;
  246. }
  247.  
  248. int
  249. check_overrun_action(unit, unit2, x, y, z, n)
  250. Unit *unit, *unit2;
  251. int x, y, z, n;
  252. {
  253.     int u, u2, u2x, u2y, u2z, u3, totcost, speed, mpavail, m;
  254.     Unit *defender;
  255.  
  256.     if (!in_play(unit))
  257.       return A_ANY_ERROR;
  258.     if (!in_play(unit2))
  259.       return A_ANY_ERROR;
  260.     if (!inside_area(x, y))
  261.       return A_ANY_ERROR;
  262.     if (n == 0)
  263.       return A_ANY_ERROR;
  264.     u = unit->type;
  265.     u2 = unit2->type;
  266.     /* (should think about this some more - overrunning into a cell with no
  267.         resistance should work perhaps, even for noncombat units) */
  268.     if (!type_can_attack(u))
  269.       return A_ANY_CANNOT_DO;
  270.     if (!has_enough_acp(unit, 1))
  271.       return A_ANY_NO_ACP;
  272.     /* Check whether we can attack from inside a transport. */
  273.     /* (although this might be legit if unit is assumed to leave transport first) */
  274.     if (unit2->transport && uu_occ_combat(u2, unit2->transport->type) == 0)
  275.       return A_ANY_ERROR;
  276.     u2x = unit2->x;  u2y = unit2->y;  u2z = unit2->z;
  277.     /* We have to be in the same cell or an adjacent one. */
  278.     if (!between(0, distance(u2x, u2y, x, y), 1))
  279.       return A_ANY_TOO_FAR;
  280.     /* Now start looking at the move costs. */
  281.     u3 = (unit2->transport ? unit2->transport->type : NONUTYPE);
  282.     totcost = total_move_cost(u2, u3, u2x, u2y, u2z, x, y, u2z);
  283.     speed = unit_speed(unit2, x, y);
  284.     mpavail = (unit->act->acp * speed) / 100;
  285.     /* Zero mp always disallows movement, unless intra-cell. */
  286.     if (mpavail <= 0 && !(u2x == x && u2y == y && u2z == u2z))
  287.       return A_MOVE_NO_MP;
  288.     /* The free mp might get us enough moves, so add it before comparing. */
  289.     if (mpavail + u_free_mp(u2) < totcost)
  290.       return A_MOVE_NO_MP;
  291.     /* We have to have a minimum level of supply to be able to attack. */
  292.     for_all_material_types(m) {
  293.     if (unit2->supply[m] < um_to_fight(u2, m))
  294.       return A_ANY_NO_MATERIAL;
  295.     }
  296.     for_all_stack(x, y, defender) {
  297.     /* (should test if units here can be attacked en masse) */
  298.         /* (should prorate ammo needs by intensity of overrun) */
  299.         if (!enough_ammo(unit2, defender))
  300.           return A_ANY_NO_MATERIAL;
  301.     }
  302.     return A_ANY_OK;
  303. }
  304.  
  305. /* Return true if the attacker defeated the defender, and can therefore
  306.    try to move into the defender's old position. */
  307.  
  308. static int
  309. one_attack(atker, defender)
  310. Unit *atker, *defender;
  311. {
  312.     int ax = atker->x, ay = atker->y, ox = defender->x, oy = defender->y;
  313.     int counter;
  314.     Side *as = atker->side, *os = defender->side;
  315.  
  316.     amain = atker;  omain = defender;
  317.     attack_unit(atker, defender);
  318.     /* Do a counterattack if appropriate. */
  319.     counter = uu_counterattack(atker->type, defender->type);
  320.     if (counter > 0) {
  321.     /* (should use value to set strength/commitment of counterattack) */
  322.     attack_unit(defender, atker);
  323.     }
  324.     reckon_damage();
  325.     see_exact(as, ax, ay);
  326.     see_exact(as, ox, oy);
  327.     see_exact(os, ax, ay);
  328.     see_exact(os, ox, oy);
  329.     update_cell_display(as, ax, ay, TRUE);
  330.     update_cell_display(as, ox, oy, TRUE);
  331.     update_cell_display(os, ax, ay, TRUE);
  332.     update_cell_display(os, ox, oy, TRUE);
  333.     all_see_cell(ax, ay);
  334.     all_see_cell(ox, oy);
  335.     attempt_to_capture_unit(atker, defender);
  336.     /* If the defender was not captured, it might turn the tables! */
  337.     /* (Note that we cannot cache the attacker's and defender's types,
  338.        because the type might have changed due to damage, and we want
  339.        to know if the new type might countercapture.) */
  340.     if (alive(defender)
  341.     && alive(atker)
  342.     && defender->side == os
  343.     && uu_countercapture(atker->type, defender->type) > 0) {
  344.     attempt_to_capture_unit(defender, atker);
  345.     }
  346.     return (alive(atker) && unit_at(ox, oy) == NULL);
  347. }
  348.  
  349. /* Fire-at action. */
  350.  
  351. /* Shooting at a given unit. */
  352.  
  353. int
  354. prep_fire_at_action(unit, unit2, defender, m)
  355. Unit *unit, *unit2, *defender;
  356. int m;
  357. {
  358.     if (unit == NULL || unit->act == NULL)
  359.       return FALSE;
  360.     if (unit2 == NULL)
  361.       return FALSE;
  362.     unit->act->nextaction.type = ACTION_FIRE_AT;
  363.     unit->act->nextaction.args[0] = defender->id;
  364.     unit->act->nextaction.args[1] = m;
  365.     unit->act->nextaction.actee = unit2->id;
  366.     return TRUE;
  367. }
  368.  
  369. int
  370. do_fire_at_action(unit, unit2, defender, m)
  371. Unit *unit, *unit2, *defender;
  372. int m;
  373. {
  374.     int ux = unit->x, uy = unit->y, ox, oy, oz;
  375.  
  376.     action_point(unit2->side, defender->x, defender->y);
  377.     action_point(defender->side, defender->x, defender->y);
  378.     update_fire_at_display(unit2->side, unit, defender, m, TRUE);
  379.     update_fire_at_display(defender->side, unit, defender, m, TRUE);
  380.     ox = defender->x;  oy = defender->y;  oz = defender->z;
  381.     amain = unit;  omain = defender;
  382.     fire_on_unit(unit, defender);
  383.     reckon_damage();
  384.     if (alive(unit))
  385.       use_up_acp(unit, u_acp_to_fire(unit2->type));
  386.     /*    if (alive(defender)) use_up_acp(defender, 1); */
  387.     /* Each side sees what happened to its own unit. */
  388.     update_unit_display(unit2->side, unit2, TRUE);
  389.     if (unit != unit2)
  390.       update_unit_display(unit->side, unit, TRUE);
  391.     update_unit_display(defender->side, defender, TRUE);
  392.     /* The attacking side also sees the remote cell. */
  393.     update_cell_display(unit2->side, ox, oy, TRUE);
  394.     update_cell_display(defender->side, ox, oy, TRUE);
  395.     /* Victim might see something in attacker's cell. */
  396.     update_cell_display(defender->side, ux, uy, TRUE);
  397.     /* Actually, everybody might be seeing the combat. */
  398.     all_see_cell(ux, uy);
  399.     all_see_cell(ox, oy);
  400.     /* Always expend the ammo (but only if m is a valid mtype). */
  401.     return A_ANY_DONE;
  402. }
  403.  
  404. /* Test a fire action for plausibility. */
  405.  
  406. int
  407. check_fire_at_action(unit, unit2, unit3, m)
  408. Unit *unit, *unit2, *unit3;
  409. int m;
  410. {
  411.     int u, u2, u3, ux, uy, uz, acp, dist, m2;
  412.  
  413.     if (!in_play(unit))
  414.       return A_ANY_ERROR;
  415.     if (!in_play(unit2))
  416.       return A_ANY_ERROR;
  417.     if (!in_play(unit3))
  418.       return A_ANY_ERROR;
  419.     /* We can't attack ourselves. */
  420.     if (unit2 == unit3)
  421.       return A_ANY_ERROR;
  422.     u = unit->type; u2 = unit2->type;  u3 = unit3->type;
  423.     ux = unit->x;  uy = unit->y;  uz = unit->z;
  424.     acp = u_acp_to_fire(u2);
  425.     if (acp < 1)
  426.       return A_ANY_CANNOT_DO;
  427.     if (!has_enough_acp(unit, acp))
  428.       return A_ANY_NO_ACP;
  429.     /* Check whether we can attack from inside a transport. */
  430.     if (unit2->transport && uu_occ_combat(u2, unit2->transport->type) == 0)
  431.       return A_ANY_ERROR;
  432.     /* Check that target is in range. */
  433.     dist = distance(ux, uy, unit3->x, unit3->y);
  434.     if (dist > u_range(u2))
  435.       return A_ANY_TOO_FAR;
  436.     if (dist < u_range_min(u2))
  437.       return A_ANY_TOO_NEAR;
  438.     if (unit2->side != NULL && unit2->side == unit3->side)
  439.       return A_ANY_ERROR;
  440.     /* Check intervening elevations. */
  441.     if (found_blocking_elevation(u2, ux, uy, uz, u3, unit3->x, unit3->y, unit3->z))
  442.       return A_ANY_ERROR;
  443.     /* We have to have a minimum level of supply to be able to attack. */
  444.     for_all_material_types(m2) {
  445.     if (unit2->supply[m2] < um_to_fight(u2, m2))
  446.       return A_ANY_NO_MATERIAL;
  447.     }
  448.     /* Check for enough of right kind of ammo. */
  449.     if (is_material_type(m)) {
  450.         if (unit->supply[m] == 0)
  451.           return A_ANY_NO_MATERIAL;
  452.     } else {
  453.         if (!enough_ammo(unit2, unit3))
  454.           return A_ANY_NO_MATERIAL;
  455.     }
  456.     return A_ANY_OK;
  457. }
  458.  
  459. /* Fire-into action. */
  460.  
  461. /* Shooting at a given location. */
  462.  
  463. int
  464. prep_fire_into_action(unit, unit2, x, y, z, m)
  465. Unit *unit, *unit2;
  466. int x, y, z, m;
  467. {
  468.     if (unit == NULL || unit->act == NULL)
  469.       return FALSE;
  470.     if (unit2 == NULL)
  471.       return FALSE;
  472.     unit->act->nextaction.type = ACTION_FIRE_INTO;
  473.     unit->act->nextaction.args[0] = x;
  474.     unit->act->nextaction.args[1] = y;
  475.     unit->act->nextaction.args[2] = z;
  476.     unit->act->nextaction.args[3] = m;
  477.     unit->act->nextaction.actee = unit2->id;
  478.     return TRUE;
  479. }
  480.  
  481. /* One can always shoot, if the cell is visible, but there might not
  482.    not be anything to hit!  No counterattacks when shooting, and the
  483.    results might not be visible to the shooter. */
  484.  
  485. int
  486. do_fire_into_action(unit, unit2, x, y, z, m)
  487. Unit *unit, *unit2;
  488. int x, y, z, m;
  489. {
  490.     int ux = unit->x, uy = unit->y, ox, oy, oz;
  491.     SideMask sidemask;
  492.     Unit *other;
  493.     Side *side;
  494.  
  495.     /* Show the firing unit doing its attack. */
  496.     update_fire_into_display(unit->side, unit2, x, y, z, m, TRUE);
  497.     /* Make up the list of sides that will see the incoming fire. */
  498.     sidemask = NOSIDES;
  499.     for_all_stack(x, y, other) {
  500.     if (other->side)
  501.       sidemask = add_side_to_set(other->side, sidemask);
  502.     }
  503.     for_all_sides(side) {
  504.     if (side_in_set(side, sidemask))
  505.           update_fire_into_display(side, unit2, x, y, z, m, TRUE);
  506.     }
  507.     /* If any units at target, hit them. */
  508.     for_all_stack(x, y, other) {
  509.     ox = other->x;  oy = other->y;  oz = other->z;
  510.     amain = unit;  omain = other;
  511.     fire_on_unit(unit2, other);
  512.     reckon_damage();
  513.     /* Each side sees what happened to its unit that is being hit. */
  514.     update_unit_display(other->side, other, TRUE);
  515.     /* The attacking side also sees the remote cell. */
  516.     update_cell_display(unit->side, ox, oy, TRUE);
  517.     update_cell_display(other->side, ox, oy, TRUE);
  518.     /* Victim might see something in attacker's cell. */
  519.     update_cell_display(other->side, ux, uy, TRUE);
  520.     /* Actually, everybody might be seeing the combat. */
  521.     all_see_cell(ux, uy);
  522.     all_see_cell(ox, oy);
  523.     /* don't take moves though! */
  524.     }
  525.     /* Firing side gets just one update. */
  526.     update_unit_display(unit2->side, unit2, TRUE);
  527.     if (unit != unit2)
  528.       update_unit_display(unit->side, unit, TRUE);
  529.     if (alive(unit))
  530.       use_up_acp(unit, u_acp_to_fire(unit2->type));
  531.     /* Always expend the ammo (but only if m is a valid material). */
  532.     /* We're always "successful", even though the bombardment may have
  533.        had little or no actual effect. */
  534.     return A_ANY_DONE;
  535. }
  536.  
  537. /* Test a shoot action for plausibility. */
  538.  
  539. int
  540. check_fire_into_action(unit, unit2, x, y, z, m)
  541. Unit *unit, *unit2;
  542. int x, y, z, m;
  543. {
  544.     int u, u2, u2x, u2y, u2z, acp, dist, m2;
  545.  
  546.     if (!in_play(unit))
  547.       return A_ANY_ERROR;
  548.     if (!in_play(unit2))
  549.       return A_ANY_ERROR;
  550.     u2x = unit2->x;  u2y = unit2->y;  u2z = unit2->z;
  551.     /* Check that target location is meaningful. */
  552.     if (!inside_area(x, y))
  553.       return A_FIRE_INTO_OUTSIDE_WORLD;
  554.     u = unit->type;
  555.     u2 = unit2->type;
  556.     acp = u_acp_to_fire(u2);
  557.     if (acp < 1)
  558.       return A_ANY_CANNOT_DO;
  559.     if (!has_enough_acp(unit, acp))
  560.       return A_ANY_NO_ACP;
  561.     /* Check whether we can attack from inside a transport. */
  562.     if (unit2->transport && uu_occ_combat(u2, unit2->transport->type) == 0)
  563.       return A_ANY_ERROR;
  564.     /* Check that target is in range. */
  565.     dist = distance(u2x, u2y, x, y);
  566.     if (dist > u_range(u2))
  567.       return A_ANY_TOO_FAR;
  568.     if (dist < u_range_min(u2))
  569.       return A_ANY_TOO_NEAR;
  570.     /* Check intervening elevations and terrain. */
  571.     if (found_blocking_elevation(u2, u2x, u2y, u2z, NONUTYPE, x, y, z))
  572.       return A_ANY_ERROR;
  573.     /* We have to have a minimum level of supply to be able to attack. */
  574.     for_all_material_types(m2) {
  575.     if (unit2->supply[m2] < um_to_fight(u2, m2))
  576.       return A_ANY_NO_MATERIAL;
  577.     }
  578.     /* Check for enough of right kind of ammo. */
  579.     if (is_material_type(m)) {
  580.         if (unit->supply[m] == 0)
  581.           return A_ANY_NO_MATERIAL;
  582.     } else {
  583.         /* should just assume amount is appropriate? */
  584.     }
  585.     return A_ANY_OK;
  586. }
  587.  
  588. int
  589. found_blocking_elevation(u, ux, uy, uz, u2, u2x, u2y, u2z)
  590. int u, ux, uy, uz, u2, u2x, u2y, u2z;
  591. {
  592. /*    int maxrise = u_elev_at_max_range(u); */
  593.  
  594.     if (world_is_flat())
  595.       return FALSE;
  596.     /* Adjacent cells can't be screened by elevation. */
  597.     /* (should accommodate possibility that target is at top of
  598.        cliff in adj and back away from its edge, thus screened) */
  599.     if (distance(ux, uy, u2x, u2y) <= 1)
  600.       return FALSE;
  601.     /* (should add scan of path) */
  602.     return FALSE;
  603. }
  604.  
  605. static void
  606. fire_on_unit(atker, other)
  607. Unit *atker, *other;
  608. {
  609.     int m, dist = distance(atker->x, atker->y, other->x, other->y);
  610.  
  611.     if (alive(atker) && alive(other)) {
  612.     if (enough_ammo(atker, other)) {
  613.         maybe_hit_unit(atker, other, TRUE, (dist > u_hit_falloff_range(atker->type)));
  614.         for_all_material_types(m) {
  615.         if (um_hit_by(other->type, m) > 0) {
  616.             atker->supply[m] -= um_consumption_per_attack(atker->type, m);
  617.         }
  618.         }
  619.         /* The *victim* can lose acp. */
  620.         use_up_acp(other, uu_acp_to_be_fired_on(other->type, atker->type));
  621.     }
  622.     }
  623.     /* (should ping victim to see if it wants to respond to the attack?) */
  624. }
  625.  
  626. /* Test to see if enough ammo is available to make the attack.
  627.    Need enough of *all* types - semi-bogus but too complicated otherwise? */
  628.  
  629. int
  630. enough_ammo(unit, other)
  631. Unit *unit, *other;
  632. {
  633.     int m;
  634.  
  635.     for_all_material_types(m) {
  636.     if (um_hit_by(other->type, m) > 0 &&
  637.         unit->supply[m] < um_consumption_per_attack(unit->type, m))
  638.       return FALSE;
  639.     }
  640.     return TRUE;
  641. }
  642.  
  643. /* Single attack, no counterattack.  Check and use ammo - usage independent
  644.    of outcome, but types used depend on unit types involved. */
  645.  
  646. static void
  647. attack_unit(atker, other)
  648. Unit *atker, *other;
  649. {
  650.     int m;
  651.  
  652.     if (alive(atker) && alive(other)) {
  653.     if (enough_ammo(atker, other)) {
  654.         maybe_hit_unit(atker, other, FALSE, FALSE);
  655.         for_all_material_types(m) {
  656.         if (um_hit_by(other->type, m) > 0) {
  657.             atker->supply[m] -= um_consumption_per_attack(atker->type, m);
  658.         }
  659.         }
  660.     }
  661.     }
  662.     /* (should ping victim to see if it wants to respond to the attack?) */
  663. }
  664.  
  665. /* Make a single hit and maybe hit some passengers also.  Power of hit
  666.    is constant, but chance is affected by terrain, quality,
  667.    and occupants' protective abilities.  If a hit is successful, it may
  668.    have consequences on the defender's occupants, but limited by the
  669.    protection that the transport provides. */
  670.  
  671. static void
  672. maybe_hit_unit(atker, other, fire, fallsoff)
  673. Unit *atker, *other;
  674. int fire, fallsoff;
  675. {
  676.     int chance, t, hit = 0, a = atker->type, o = other->type;
  677.     int cxpeffect, cxpmax, effect, prot;
  678.     int dist, disthit, rangedelta, hitdelta, rangeamt;
  679.     int dmgspec;
  680.     int hitmovietype;
  681.     Unit *occ, *unit2;
  682.     Side *side3;
  683.     
  684.     Dprintf("%s tries to hit %s", unit_desig(atker), unit_desig(other));
  685.     if (fire && uu_fire_hit(a, o) != -1)
  686.       chance = uu_fire_hit(a, o);
  687.     else
  688.       chance = uu_hit(a, o);
  689.     /* Combat experience tends to raise the hit chance, so do that first. */
  690.     cxpmax = u_cxp_max(a);
  691.     if (cxpmax > 0 && atker->cxp > 0) {
  692.     cxpeffect = uu_hit_cxp(a, o);
  693.     if (cxpeffect != 100) {
  694.         effect = 100 + (atker->cxp * (cxpeffect - 100)) / cxpmax;
  695.         chance = (chance * effect) / 100;
  696.     }
  697.     }
  698.     /* (should modify due to cxp of defender too) */
  699.     /* Account for terrain effects. */
  700.     t = terrain_at(atker->x, atker->y);
  701.     chance = (chance * ut_attack_terrain_effect(a, t)) / 100;
  702.     t = terrain_at(other->x, other->y);
  703.     chance = (chance * ut_defend_terrain_effect(o, t)) / 100;
  704.     /* Account for protective units nearby. */
  705.     for_all_occupants(other, occ) {
  706.     if (in_play(occ) && completed(occ)) {
  707.         prot = uu_protection(occ->type, o);
  708.         if (prot != 100)
  709.           chance = (chance * prot) / 100;
  710.     }
  711.     }
  712.     if (other->transport
  713.     && in_play(other->transport)
  714.     && completed(other->transport)) {
  715.     prot = uu_protection(other->transport->type, o);
  716.     if (prot != 100)
  717.       chance = (chance * prot) / 100;
  718.     }
  719.     for_all_stack(other->x, other->y, unit2) {
  720.     if (unit2 != other
  721.         && in_play(unit2)
  722.         && completed(unit2)
  723.         && unit2->side == other->side) {
  724.         prot = uu_stack_protection(unit2->type, o);
  725.         if (prot != 100)
  726.           chance = (chance * prot) / 100;
  727.     }
  728.     }
  729.     if (fallsoff) {
  730.     dist = distance(atker->x, atker->y, other->x, other->y);
  731.         disthit = uu_hit_max_range_effect(a, o);
  732.         rangedelta = u_range(a) - u_hit_falloff_range(a);
  733.         rangeamt = dist - u_hit_falloff_range(a);
  734.         hitdelta = uu_hit(a, o) - disthit;
  735.         chance = uu_hit(a, o)
  736.       - ((uu_hit(a, o) - disthit) * rangeamt) / rangedelta;
  737.     }
  738.     Dprintf(", probability of hit is %d%%", chance);
  739.     /* Compute the hit itself. */
  740.     if (probability(chance)) {
  741.     if (fire && uu_fire_damage(a, o) != -1)
  742.           dmgspec = uu_fire_damage(a, o);
  743.         else
  744.           dmgspec = uu_damage(a, o);
  745.         /* Account for attacker's experience. */
  746.     if (cxpmax > 0 && atker->cxp > 0) {
  747.         cxpeffect = uu_damage_cxp(a, o);
  748.         if (cxpeffect != 100) {
  749.         effect = 100 + (atker->cxp * (cxpeffect - 100)) / cxpmax;
  750.         dmgspec = multiply_dice(dmgspec, effect);
  751.         }
  752.     }
  753.     hit = roll_dice(dmgspec);
  754.     }
  755.     if (hit > 0) {
  756.         Dprintf(", damage will be %d hp", hit);
  757.     } else {
  758.         Dprintf(", missed");
  759.     }
  760.     /* (should record a raw statistic?) */
  761.     /* Ablation is a chance for occupants or stack to take part of a hit themselves. */
  762.     if (hit > 0) {
  763.     /* (should decide how ablation computed) */
  764.     }
  765.     if (hit > 0) {
  766.     chance = uu_retreat_chance(a, o);
  767.     /* (should adjust chance by morale etc) */
  768.     if (probability(chance)) {
  769.         if (retreat_unit(other, atker)) {
  770.         notify_combat(other, atker, "%s retreats!");
  771.         hit = 0; /* should only be reduced hit, may still be > 0 */
  772.         }
  773.     }
  774.     }
  775.     hit_unit(other, hit, atker);
  776.     for_all_sides(side3) {
  777.         if (active_display(side3)
  778.         && (all_see_all
  779.                 || (side3 == atker->side || side3 == other->side))) {
  780.         hitmovietype = ((hit >= other->hp) ? movie_death :
  781.                 ((hit > 0) ? movie_hit : movie_miss));
  782.         schedule_movie(side3, hitmovietype, other->id);
  783.         }
  784.     }
  785.     Dprintf("\n");
  786.     /* Recurse into occupants, maybe hit them too.  */
  787.     for_all_occupants(other, occ) {
  788.     if (probability(100 - uu_protection(o, occ->type))) {
  789.         maybe_hit_unit(atker, occ, fire, fallsoff);
  790.     }
  791.     }
  792.     /* We get combat experience only if there could have been some damage. */
  793.     if (chance > 0) {
  794.         if (atker->cxp < u_cxp_max(a))
  795.           atker->cxp += uu_cxp_per_combat(a, o);
  796.         if (other->cxp < u_cxp_max(o))
  797.           other->cxp += uu_cxp_per_combat(o, a);
  798.         /* Occupants already gained their experience in the recursive call. */
  799.     }
  800. }
  801.  
  802. /* Do the hit itself. */
  803.  
  804. static void
  805. hit_unit(unit, hit, atker)
  806. Unit *unit, *atker;
  807. int hit;
  808. {
  809.     int u = unit->type, hpmin;
  810.  
  811.     /* Some units might detonate automatically upon being hit. */
  812.     if (hit > 0
  813.         && atker != NULL
  814.         && probability(uu_detonate_on_hit(u, atker->type))
  815.         && !was_detonated(unit)) {
  816.         detonate_unit(unit, unit->x, unit->y, unit->z);
  817.         /* If the detonating unit still exists, then continue
  818.            on to normal damage computation. */
  819.     }
  820.     /* Record the loss of hp. */
  821.     unit->hp2 -= hit;
  822.     /* Attacker might not be able to do any more damage.  Note that the
  823.        positioning of this code is such that all the usual side effects
  824.        of combat happen, but the victim doesn't get any more worse off
  825.        than it is already. */
  826.     if (atker != NULL) {
  827.     hpmin = uu_hp_min(atker->type, u);
  828.     if (hpmin > 0 && hpmin > unit->hp2) {
  829.         unit->hp2 = hpmin;
  830.     }
  831.     }
  832.     /* Maybe record for statistical analysis. */
  833.     /* (this is only useful if code always goes through here - is that true?) */
  834.     if (atker != NULL && atker->side != NULL) {
  835.     if (atker->side->atkstats[atker->type] == NULL)
  836.       atker->side->atkstats[atker->type] = (long *) xmalloc(numutypes * sizeof(long));
  837.     if (atker->side->hitstats[atker->type] == NULL)
  838.       atker->side->hitstats[atker->type] = (long *) xmalloc(numutypes * sizeof(long));
  839.     ++((atker->side->atkstats[atker->type])[u]);
  840.     (atker->side->hitstats[atker->type])[u] += hit;
  841.     }
  842.     /* Some units may detonate automatically just before dying. */
  843.     if (hit > 0
  844.         && unit->hp2 <= 0
  845.         && probability(u_detonate_on_death(u))
  846.         && !was_detonated(unit)) {
  847.     detonate_unit(unit, unit->x, unit->y, unit->z);
  848.     }
  849. }
  850.  
  851. /* Hits on the main units have to be done later, so that mutual
  852.    destruction works properly.  This function also does all the notifying. */
  853.  
  854. /* (What if occupants change type when killed, but transport vanishes?) */
  855.  
  856. void
  857. reckon_damage()
  858. {
  859.     /* Entertain everybody. */
  860.     play_movies(ALLSIDES);
  861.     /* Report the damage in more detail, now before the actual damage
  862.        is taken (which may cause many units to disappear). */
  863.     /* Normally we report the defender and then the attacker's damage,
  864.        but if the defender dies, we report its counterattack results
  865.        first and its death second. */
  866.     if (!(omain->hp2 <= 0 && amain->hp2 > 0)) {
  867.     report_damage(omain, amain, omain);
  868.     report_damage(amain, omain, amain);
  869.     } else {
  870.     report_damage(amain, omain, amain);
  871.     report_damage(omain, amain, omain);
  872.     }
  873.     damage_unit(omain, combat_dmg);
  874.     damage_unit(amain, combat_dmg);
  875. }
  876.  
  877. static void
  878. reckon_damage_here(x, y)
  879. int x, y;
  880. {
  881.     Unit *unit;
  882.  
  883.     for_all_stack(x, y, unit) {
  884.     damage_unit(unit, combat_dmg);
  885.     }
  886. }
  887.  
  888. void
  889. reckon_damage_around(x, y, r)
  890. int x, y, r;
  891. {
  892.     if (r > 0) {
  893.     apply_to_area(x, y, r, reckon_damage_here);
  894.     } else {
  895.     reckon_damage_here(x, y);
  896.     }
  897. }
  898.  
  899. static void
  900. report_damage(unit, atker, mainunit)
  901. Unit *unit, *atker, *mainunit;
  902. {
  903.     Unit *occ;
  904.  
  905.     if (unit->hp2 <= 0) {
  906.     if (unit == mainunit) {
  907.         notify_combat(atker, unit, "%s destroys %s!");
  908.     } else {
  909.         notify_combat(unit, atker, "  (and destroys occupant %s!)");
  910.     }
  911.     } else if (unit->hp2 < unit->hp) {
  912.     if (unit == mainunit) {
  913.         notify_combat(atker, unit, "%s hits %s!");
  914.     } else {
  915.         notify_combat(unit, atker, "  (and hits occupant %s!)");
  916.     }
  917.     } else {
  918.     /* messages about misses not too useful */
  919.     }
  920.     for_all_occupants(unit, occ) {
  921.     report_damage(occ, atker, mainunit);
  922.     }
  923. }
  924.  
  925. /* Make the intended damage become real, and do any consequences. */
  926.  
  927. void
  928. damage_unit(unit, dmgreason)
  929. Unit *unit;
  930. enum damage_reasons dmgreason;
  931. {
  932.     int newacp;
  933.     HistEventType hevttype;
  934.     Obj *dameff;
  935.     Unit *occ;
  936.  
  937.     /* Process all the occupants first. */
  938.     for_all_occupants(unit, occ) {
  939.     damage_unit(occ, dmgreason);
  940.     }
  941.     /* If no damage was recorded, just return. */
  942.     if (unit->hp2 == unit->hp)
  943.       return;
  944.     /* If unit is to die, do the consequences. */
  945.     if (unit->hp2 <= 0) {
  946.     if (u_wrecked_type(unit->type) == NONUTYPE) {
  947.         /* (should let occupants escape now?) */
  948.         hevttype = (dmgreason == combat_dmg ? H_UNIT_KILLED :
  949.             (dmgreason == accident_dmg ? H_UNIT_DIED_IN_ACCIDENT :
  950.              0));
  951.         kill_unit(unit, hevttype);
  952.     } else {
  953.         hevttype = (dmgreason == combat_dmg ? H_UNIT_WRECKED :
  954.             (dmgreason == accident_dmg ? H_UNIT_WRECKED_IN_ACCIDENT :
  955.              0));
  956.         change_unit_type(unit, u_wrecked_type(unit->type), hevttype);
  957.         /* Restore to default hp for the new type. */
  958.         unit->hp = unit->hp2 = u_hp(unit->type);
  959.         /* Get rid of occupants if overfull. */
  960.         eject_excess_occupants(unit);
  961.         /* change_unit_type already reported the wrecking as an event,
  962.            do we need any additional reportage? */
  963.     }
  964.     } else {
  965.     record_event(H_UNIT_DAMAGED, add_side_to_set(unit->side, NOSIDES),
  966.              unit->id, unit->hp, unit->hp2);
  967.     /* Change the unit's hp. */
  968.     unit->hp = unit->hp2;
  969.     /* Perhaps adjust the acp down. */
  970.     if (unit->act != NULL
  971.         && unit->act->acp > 0
  972.         && (dameff = u_acp_damage_effect(unit->type)) != lispnil) {
  973.         newacp = damaged_acp(unit, dameff);
  974.         /* The damaged acp limits the remaining acp, rather than trying
  975.            to do some sort of proportional adjustment, which would be
  976.            hard to get right. */
  977.         /* (should account for occupant effects on acp) */
  978.         unit->act->acp = min(unit->act->acp, newacp);
  979.     }
  980.     }
  981.     /* Clear any detonation flag that might have been set. */
  982.     if (alive(unit))
  983.       set_was_detonated(unit, FALSE);
  984.     /* Let the unit's owner know about all this. */
  985.     update_unit_display(unit->side, unit, TRUE);
  986. }
  987.  
  988. /* Retreat is a special kind of movement that a unit uses to avoid
  989.    damage during combat. It bypasses some of the normal move rules. */
  990.  
  991. static int
  992. retreat_unit(unit, atker)
  993. Unit *unit, *atker;
  994. {
  995.     int dir;
  996.     extern int retreating_from;
  997.  
  998.     retreating_from = atker->type;
  999.     if (unit->x == atker->x && unit->y == atker->y) {
  1000.         dir = random_dir();
  1001.     } else {
  1002.         dir = approx_dir(unit->x - atker->x, unit->y - atker->y);
  1003.     }
  1004.     if (retreat_in_dir(unit, dir))
  1005.       return TRUE;
  1006.     if (flip_coin()) {
  1007.         if (retreat_in_dir(unit, left_dir(dir)))
  1008.           return TRUE;
  1009.         if (retreat_in_dir(unit, right_dir(dir)))
  1010.           return TRUE;
  1011.     } else {
  1012.         if (retreat_in_dir(unit, right_dir(dir)))
  1013.           return TRUE;
  1014.         if (retreat_in_dir(unit, left_dir(dir)))
  1015.           return TRUE;
  1016.     }
  1017.     retreating_from = NONUTYPE;
  1018.     return FALSE;
  1019. }
  1020.  
  1021. static int
  1022. retreat_in_dir(unit, dir)
  1023. Unit *unit;
  1024. int dir;
  1025. {
  1026.     int nx, ny, rslt;
  1027.     extern int retreating;
  1028.     extern int retreating_from;
  1029.  
  1030.     /* (should it be possible for a unit to retreat out of the world?) */
  1031.     if (!interior_point_in_dir(unit->x, unit->y, dir, &nx, &ny))
  1032.       return FALSE;
  1033.     retreating = TRUE;
  1034.     rslt = check_move_action(unit, unit, nx, ny, unit->z);
  1035.     if (!valid(rslt))
  1036.       return FALSE;
  1037.     do_move_action(unit, unit, nx, ny, unit->z);
  1038.     retreating = FALSE;
  1039.     retreating_from = NONUTYPE;
  1040.     return TRUE;
  1041. }
  1042.  
  1043. /* Capture action. */
  1044.  
  1045. /* Prepare a capture action to be executed later. */
  1046.  
  1047. int
  1048. prep_capture_action(unit, unit2, unit3)
  1049. Unit *unit, *unit2, *unit3;
  1050. {
  1051.     if (unit == NULL || unit->act == NULL)
  1052.       return FALSE;
  1053.     if (unit2 == NULL)
  1054.       return FALSE;
  1055.     unit->act->nextaction.type = ACTION_CAPTURE;
  1056.     unit->act->nextaction.args[0] = unit3->id;
  1057.     unit->act->nextaction.actee = unit2->id;
  1058.     return TRUE;
  1059. }
  1060.  
  1061. /* Execute a capture action. */
  1062.  
  1063. int
  1064. do_capture_action(unit, unit2, unit3)
  1065. Unit *unit, *unit2, *unit3;
  1066. {
  1067.     int rslt;
  1068.  
  1069.     attempt_to_capture_unit(unit2, unit3);
  1070.     use_up_acp(unit, uu_acp_to_capture(unit2->type, unit3->type));
  1071.     if (unit3->side == unit2->side)
  1072.       rslt = A_CAPTURE_SUCCEEDED;
  1073.     else
  1074.       rslt = A_CAPTURE_FAILED;
  1075.     return rslt;
  1076. }
  1077.  
  1078. /* Check the validity of a capture action. */
  1079.  
  1080. int
  1081. check_capture_action(unit, unit2, unit3)
  1082. Unit *unit, *unit2, *unit3;
  1083. {
  1084.     int u, u2, u3, acp, m;
  1085.  
  1086.     if (!in_play(unit))
  1087.       return A_ANY_ERROR;
  1088.     if (!in_play(unit2))
  1089.       return A_ANY_ERROR;
  1090.     if (!in_play(unit3))
  1091.       return A_ANY_ERROR;
  1092.     /* We can't capture ourselves. */
  1093.     if (unit2 == unit3)
  1094.       return A_ANY_ERROR;
  1095.     /* We can't capture units on our side. */
  1096.     if (unit2->side == unit3->side)
  1097.       return A_ANY_ERROR;    
  1098.     u = unit->type;
  1099.     u2 = unit2->type;
  1100.     u3 = unit3->type;
  1101.     acp = uu_acp_to_capture(u2, u3);
  1102.     if (acp < 1)
  1103.       return A_ANY_CANNOT_DO;
  1104.     if (capture_chance(u2, u3, unit3->side) == 0)
  1105.       return A_ANY_CANNOT_DO;
  1106.     if (distance(unit2->x, unit2->y, unit3->x, unit3->y) > 1)
  1107.       return A_ANY_ERROR;
  1108.     if (!has_enough_acp(unit, acp))
  1109.       return A_ANY_NO_ACP;
  1110.     /* We have to have a minimum level of supply to be able to capture. */
  1111.     for_all_material_types(m) {
  1112.     if (unit2->supply[m] < um_to_fight(u2, m))
  1113.       return A_ANY_NO_MATERIAL;
  1114.     }
  1115.     return A_ANY_OK;
  1116. }
  1117.  
  1118. /* Handle capture possibility and repulse/slaughter. */
  1119.  
  1120. /* The chance to capture an enemy is modified by several factors.
  1121.    Neutrals have a different chance to be captured, and presence of
  1122.    occupants should also has an effect.  Can't capture anything that is
  1123.    on a kind of terrain that the capturer can't go on, unless victim has
  1124.    "bridge effect". */
  1125.  
  1126. /* (Need a little better treatment of committed assaults, where lack of
  1127.    success == death.) */
  1128.  
  1129. static void
  1130. attempt_to_capture_unit(atker, other)
  1131. Unit *atker, *other;
  1132. {
  1133.     int a = atker->type, o = other->type, chance, prot;
  1134.     int ox = other->x, oy = other->y;
  1135.     Unit *occ;
  1136.     Side *as = atker->side, *os = other->side;
  1137.     
  1138.     chance = capture_chance(a, o, other->side);
  1139.     if (alive(atker) && alive(other) && chance > 0) {
  1140.     if (impassable(atker, ox, oy) && !uu_bridge(o, a))
  1141.       return;
  1142.     /* Can possibly detonate on *any* attempt to capture! */
  1143.     if (probability(uu_detonate_on_capture(o, a))
  1144.         && !was_detonated(other)) {
  1145.         detonate_unit(other, other->x, other->y, other->z);
  1146.         /* Might not be possible to capture anything anymore. */
  1147.         if (!alive(atker) || !alive(other))
  1148.           return;
  1149.         /* Types of units might have changed, recalc things. */
  1150.         a = atker->type;  o = other->type;
  1151.         as = atker->side;  os = other->side;
  1152.         chance = capture_chance(a, o, other->side);
  1153.     }
  1154.     /* Occupants can protect the transport. */
  1155.     for_all_occupants(other, occ) {
  1156.         if (is_active(occ)) {
  1157.             prot = uu_protection(occ->type, o);
  1158.         chance = (chance * prot) / 100;
  1159.         }
  1160.     }
  1161.     /* Test whether the capture actually happens. */
  1162.     if (probability(chance)) {
  1163.         capture_unit(atker, other);
  1164.     } else if (atker->transport != NULL && 
  1165.            (impassable(atker, ox, oy) ||
  1166.             impassable(atker, atker->x, atker->y))) {
  1167.         /* was the capture attempt a one-way trip? */
  1168.         /* (should fix the test above - needs to be more accurate) */
  1169.         notify_combat(other, atker, "%s resists capture; %s slaughtered!");
  1170.         kill_unit(atker, H_UNIT_KILLED /* should be something appropriate */);
  1171.     } else {
  1172.         notify_combat(other, atker, "%s throws back %s!");
  1173.         /* (should record failed attempt to capture?) */
  1174.     }
  1175.     if (chance > 0) {
  1176.         if (atker->cxp < u_cxp_max(a))
  1177.           atker->cxp += uu_cxp_per_capture(a, o);
  1178.         /* (should not increment if side just changed?) */
  1179.         if (other->cxp < u_cxp_max(o))
  1180.           other->cxp += uu_cxp_per_capture(o, a);
  1181.     }
  1182.     }
  1183. }
  1184.  
  1185. int
  1186. capture_chance(u, u2, side2)
  1187. int u, u2;
  1188. Side *side2;
  1189. {
  1190.     int chance, indepchance;
  1191.  
  1192.     chance = uu_capture(u, u2);
  1193.     if (side2 != NULL)
  1194.       return chance;
  1195.     indepchance = uu_indep_capture(u, u2);
  1196.     return (indepchance < 0 ? chance : indepchance);
  1197. }
  1198.  
  1199. /* There are many consequences of a unit being captured. */
  1200.  
  1201. void
  1202. capture_unit(unit, pris)
  1203. Unit *unit, *pris;
  1204. {
  1205.     int u = unit->type, px = pris->x, py = pris->y;
  1206.     Unit *occ;
  1207.     Side *ps = pris->side, *us = unit->side, *newside;
  1208.  
  1209.     newside = unit->side;
  1210.     /* Return a unit to its original side if we are buds with that side. */
  1211.     if (pris->origside != newside && trusted_side(us, pris->origside))
  1212.       newside = pris->origside;
  1213.     if (probability(uu_scuttle(pris->type, unit->type))) {
  1214.     /* (should add terrain effect on success too) */
  1215.     /* (should characterize as a scuttle) */
  1216.     kill_unit(pris, H_UNIT_DISBANDED);
  1217.     }
  1218.     if (!unit_allowed_on_side(pris, newside)) {
  1219.     kill_unit(pris, H_UNIT_KILLED);
  1220.     }
  1221.     if (alive(pris)) {
  1222.     if (newside == pris->origside)
  1223.       notify_combat(unit, pris, "%s liberates %s!");
  1224.     else
  1225.       notify_combat(unit, pris, "%s captures %s!");
  1226.     /* Decide the fate of each occupant of our prisoner. */
  1227.     for_all_occupants(pris, occ) {
  1228.         capture_occupant(unit, pris, occ, newside);
  1229.     }
  1230.     /* The change of side itself.  This happens recursively to any
  1231.        remaining occupants as well. */
  1232.     change_unit_side(pris, newside, H_UNIT_CAPTURED, unit);
  1233.     /* Garrison the newly-captured unit with hp from the capturing unit. */
  1234.     garrison_unit(unit, pris);
  1235.     capture_unit_2(unit, pris, ps);
  1236.     /* The people at the new location may change sides immediately. */
  1237.     if (people_sides_defined()
  1238.         && any_people_side_changes
  1239.         && probability(people_surrender_chance(pris->type, px, py))) {
  1240.         change_people_side_around(px, py, pris->type, unit->side);
  1241.     }
  1242.     }
  1243.     /* Update everybody's view of the situation. */
  1244.     see_exact(ps, px, py);
  1245.     update_cell_display(ps, px, py, TRUE);
  1246.     all_see_cell(px, py);
  1247. }
  1248.  
  1249. /* Given that the main unit is going to be captured, decide what each occupant
  1250.    will do. */
  1251.  
  1252. static void
  1253. capture_occupant(unit, pris, occ, newside)
  1254. Unit *unit, *pris, *occ;
  1255. Side *newside;
  1256. {
  1257.     int u = unit->type;
  1258.     Unit *subocc;
  1259.  
  1260.     if (probability(uu_occ_escape(u, occ->type))) {
  1261.     /* The occupant escapes, along with all its suboccupants. */
  1262.     /* (should impl by moving to nearby cells?) */
  1263.     } else if (0 /* (should allow for occ scuttling also) */) {
  1264.     } else if (/* u_change_side(occ->type) || */ capture_chance(u, occ->type, occ->side) > 0) {
  1265.     /* Side change will actually happen later. */
  1266.     for_all_occupants(occ, subocc) {
  1267.         capture_occupant(unit, occ, subocc, newside);
  1268.     }
  1269.     } else {
  1270.     /* Occupant can't live as a prisoner, but suboccs might. */
  1271.     for_all_occupants(occ, subocc) {
  1272.         capture_occupant(unit, occ, subocc, newside);
  1273.     }
  1274.     /* Any suboccupants that didn't escape will die. */
  1275.     /* (what if subocc captured tho? should move elsewhere) */
  1276.     kill_unit(occ, H_UNIT_KILLED);
  1277.     }
  1278. }
  1279.  
  1280. static void
  1281. capture_unit_2(unit, pris, prevside)
  1282. Unit *unit, *pris;
  1283. Side *prevside;
  1284. {
  1285.     Unit *occ;
  1286.  
  1287.     /* Our new unit's experience might be higher or lower, depending on what
  1288.        capture really means (change of crew perhaps). */
  1289.     pris->cxp = (pris->cxp * u_cxp_on_capture(pris->type)) / 100;
  1290.     pris->cxp = min(unit->cxp, u_cxp_max(pris->type));
  1291.     /* Clear any actions and plans. */
  1292.     /* Don't use init_unit_actorstate!  We just want to cancel any pending
  1293.        action, but leave all the acp values untouched. */
  1294.     if (pris->act)
  1295.       pris->act->nextaction.type = ACTION_NONE;
  1296.     /* (should probably adjust side's acp sums by new unit's amounts) */
  1297.     init_unit_plan(pris);
  1298.     /* Assign a number to this unit if it should have one. */
  1299.     assign_unit_number(pris);
  1300.     /* Likewise for occupants. */
  1301.     for_all_occupants(pris, occ) {
  1302.     capture_unit_2(unit, occ, prevside);
  1303.     }
  1304. }
  1305.  
  1306. /* A detonate action just blasts the vicinity. */
  1307.  
  1308. int
  1309. prep_detonate_action(unit, unit2, x, y, z)
  1310. Unit *unit, *unit2;
  1311. int x, y, z;
  1312. {
  1313.     if (unit == NULL || unit->act == NULL)
  1314.       return FALSE;
  1315.     if (unit2 == NULL)
  1316.       return FALSE;
  1317.     unit->act->nextaction.type = ACTION_DETONATE;
  1318.     unit->act->nextaction.args[0] = x;
  1319.     unit->act->nextaction.args[1] = y;
  1320.     unit->act->nextaction.args[2] = z;
  1321.     unit->act->nextaction.actee = unit2->id;
  1322.     return TRUE;
  1323. }
  1324.  
  1325. int
  1326. do_detonate_action(unit, unit2, x, y, z)
  1327. Unit *unit, *unit2;
  1328. int x, y, z;
  1329. {
  1330.     int u2 = unit2->type;
  1331.  
  1332.     detonate_unit(unit2, x, y, z);
  1333.     /* Note that if the maxrange is further than the actual range of this
  1334.        detonation, only just-damaged units will be looked at. */
  1335.     reckon_damage_around(x, y, max_u_detonate_effect_range);
  1336.     /* Unit might have detonated outside its range of effect, so need this to make
  1337.        its own damage is accounted for. */
  1338.     if (alive(unit2))
  1339.       reckon_damage_around(unit2->x, unit2->y, 0);
  1340.     use_up_acp(unit, u_acp_to_detonate(u2));
  1341.     return A_ANY_DONE;
  1342. }
  1343.  
  1344. int
  1345. check_detonate_action(unit, unit2, x, y, z)
  1346. Unit *unit, *unit2;
  1347. int x, y, z;
  1348. {
  1349.     int u, u2, acp;
  1350.  
  1351.     if (!in_play(unit))
  1352.       return A_ANY_ERROR;
  1353.     if (!in_play(unit2))
  1354.       return A_ANY_ERROR;
  1355.     if (!inside_area(x, y))
  1356.       return A_ANY_ERROR;
  1357.     u = unit->type;
  1358.     u2 = unit2->type;
  1359.     /* The unit must actually be able to detonate. */
  1360.     acp = u_acp_to_detonate(u2);
  1361.     if (acp < 1)
  1362.       return A_ANY_CANNOT_DO;
  1363.     /* Can only detonate in our own or an adjacent cell. */
  1364.     /* (In other words, the detonating unit doesn't get to teleport
  1365.        its detonation effects to any desired faraway location.) */
  1366.     if (distance(unit2->x, unit2->y, x, y) > 1)
  1367.       return A_ANY_ERROR;
  1368.     if (!has_enough_acp(unit, acp))
  1369.       return A_ANY_NO_ACP;
  1370.     return A_ANY_OK;
  1371. }
  1372.  
  1373. static int tmpdetx, tmpdety;
  1374.  
  1375. /* Actual detonation may occur by explicit action or automatically; this
  1376.    routine makes the detonation effects happen, pyrotechnics and all. */
  1377.  
  1378. int
  1379. detonate_unit(unit, x, y, z)
  1380. Unit *unit;
  1381. int x, y, z;
  1382. {
  1383.     int u = unit->type, dir, x1, y1, dmg, t, maxrange;
  1384.     Unit *unit2;
  1385.  
  1386.     if (max_u_detonate_effect_range < 0) {
  1387.     int u2, u3, range;
  1388.  
  1389.     for_all_unit_types(u2) {
  1390.         for_all_unit_types(u3) {
  1391.         range = uu_detonation_range(u2, u3);
  1392.         max_u_detonate_effect_range =
  1393.           max(range, max_u_detonate_effect_range);
  1394.         }
  1395.     }
  1396.     }
  1397.     if (max_t_detonate_effect_range < 0) {
  1398.     int u2, t, range;
  1399.  
  1400.     for_all_unit_types(u2) {
  1401.         for_all_terrain_types(t) {
  1402.         range = ut_detonation_range(u2, t);
  1403.         max_t_detonate_effect_range =
  1404.           max(range, max_t_detonate_effect_range);
  1405.         }
  1406.     }
  1407.     }
  1408.     notify_combat(unit, unit, "%s detonates!");
  1409.     set_was_detonated(unit, TRUE);
  1410.     /* Hit the detonating unit first. */
  1411.     hit_unit(unit, u_hp_per_detonation(u), NULL);
  1412.     /* Hit units at ground zero. */
  1413.     for_all_stack(x, y, unit2) {
  1414.         if (unit2 != unit) {
  1415.         hit_unit(unit2, uu_detonation_damage_at(u, unit2->type), unit);
  1416.     }
  1417.     }
  1418.     damage_terrain(u, x, y);
  1419.     /* Hit units and/or terrain in adjacent cells, if this is defined. */
  1420.     if (max_u_detonate_effect_range >= 1) {
  1421.         for_all_directions(dir) {
  1422.         if (interior_point_in_dir(x, y, dir, &x1, &y1)) {
  1423.         for_all_stack(x1, y1, unit2) {
  1424.             dmg = uu_detonation_damage_adj(u, unit2->type);
  1425.             hit_unit(unit2, dmg, unit);
  1426.         }
  1427.         }
  1428.     }
  1429.     }
  1430.     if (max_t_detonate_effect_range >= 1) {
  1431.         for_all_directions(dir) {
  1432.         if (point_in_dir(x, y, dir, &x1, &y1)) {
  1433.         damage_terrain(u, x1, y1);
  1434.         }
  1435.     }
  1436.     }
  1437.     /* Hit units that are further away. */
  1438.     maxrange = max(max_u_detonate_effect_range, max_t_detonate_effect_range);
  1439.     if (maxrange >= 2) {
  1440.     tmpunit = unit;
  1441.     tmpdetx = x;  tmpdety = y;
  1442.     apply_to_area(x, y, maxrange, detonate_on_cell);
  1443.     }
  1444.     /* (should test compatibility of any new terrain types with each other;
  1445.         only after changes over with) */
  1446.     return TRUE;
  1447. }
  1448.  
  1449. static void
  1450. detonate_on_cell(x, y)
  1451. int x, y;
  1452. {
  1453.     int dist, dmg, sdmg, t;
  1454.     Unit *unit2;
  1455.  
  1456.     dist = distance(tmpdetx, tmpdety, x, y);
  1457.     if (dist > 1 && dist <= max_u_detonate_effect_range) {
  1458.     for_all_stack(x, y, unit2) {
  1459.         if (dist <= uu_detonation_range(tmpunit->type, unit2->type)) {
  1460.         dmg = uu_detonation_damage_adj(tmpunit->type, unit2->type);
  1461.         /* Reduce by inverse square of the distance. */
  1462.         sdmg = (dmg * 100) / (dist * dist);
  1463.         dmg = prob_fraction(sdmg);
  1464.         hit_unit(unit2, dmg, tmpunit);
  1465.         }
  1466.     }
  1467.     }
  1468.     if (dist > 1 && dist <= max_t_detonate_effect_range) {
  1469.     damage_terrain(tmpunit->type, x, y);
  1470.     }
  1471. }
  1472.  
  1473. void
  1474. damage_terrain(u, x, y)
  1475. int u, x, y;
  1476. {
  1477.     int t, t2, dir, x1, y1;
  1478.  
  1479.     /* Damage the cell's terrain. */
  1480.     t = terrain_at(x, y);
  1481.     if (probability(ut_detonation_damage(u, t))) {
  1482.     t2 = damaged_terrain_type(t);
  1483.     if (t2 == NONTTYPE) {
  1484.         run_error("bad damaged type?");
  1485.         return;
  1486.     } else if (t2 != t) {
  1487.         change_terrain_type(x, y, t2);
  1488.     }
  1489.     }
  1490.     /* Apply to auxiliary terrain also. */
  1491.     if (1 /* if any aux terrain */) {
  1492.     for_all_terrain_types(t) {
  1493.         switch (t_subtype(t)) {
  1494.           case cellsubtype:
  1495.         /* We already did this one. */
  1496.             break;
  1497.           case bordersubtype:
  1498.         for_all_directions(dir) {
  1499.             if (1) {
  1500.             if (border_at(x, y, dir, t)
  1501.                 && probability(ut_detonation_damage(u, t))) {
  1502.                 t2 = damaged_terrain_type(t);
  1503.                 if (t2 == NONTTYPE) {
  1504.                 set_border_at(x, y, dir, t, FALSE);
  1505.                 } else if (t2 != t) {
  1506.                 set_border_at(x, y, dir, t, FALSE);
  1507.                 set_border_at(x, y, dir, t2, TRUE);
  1508.                 /* There is potentially a problem with some
  1509.                    game designs here; if the new type t2 can
  1510.                    also be damaged by the detonation, then
  1511.                    the loop here will damage it in turn, at
  1512.                    least if t2 *follows* t in the list of terrain
  1513.                    types.  Preventing this would require a lot of
  1514.                    buffering, so it's left as a limitation for now. */
  1515.                 }
  1516.             }
  1517.             }
  1518.         }
  1519.             break;
  1520.           case connectionsubtype:
  1521.         for_all_directions(dir) {
  1522.             if (1) {
  1523.             if (connection_at(x, y, dir, t)
  1524.                 && probability(ut_detonation_damage(u, t))) {
  1525.                 t2 = damaged_terrain_type(t);
  1526.                 if (t2 == NONTTYPE) {
  1527.                 set_connection_at(x, y, dir, t, FALSE);
  1528.                 } else if (t2 != t) {
  1529.                 set_connection_at(x, y, dir, t, FALSE);
  1530.                 set_connection_at(x, y, dir, t2, TRUE);
  1531.                 }
  1532.             }
  1533.             }
  1534.         }
  1535.             break;
  1536.           case coatingsubtype:
  1537.         /* don't know how to damage coatings yet */
  1538.             break;
  1539.         }
  1540.     }
  1541.     }
  1542. }
  1543.  
  1544. int
  1545. damaged_terrain_type(t)
  1546. int t;
  1547. {
  1548.     int t2, tot, othertot, test, sum, rslt;
  1549.  
  1550.     tot = othertot = 0;
  1551.     for_all_terrain_types(t2) {
  1552.     if (t_subtype(t2) == t_subtype(t)) {
  1553.         tot += tt_damaged_type(t, t2);
  1554.     } else {
  1555.         othertot += tt_damaged_type(t, t2);
  1556.     }
  1557.     }
  1558.     rslt = NONTTYPE;
  1559.     if ((tot + othertot) > 0) {
  1560.         test = xrandom(tot + othertot);
  1561.         sum = 0;
  1562.         for_all_terrain_types(t2) {
  1563.         if (t_subtype(t2) == t_subtype(t)) {
  1564.             sum += tt_damaged_type(t, t2);
  1565.         if (test < sum) {
  1566.             rslt = t2;
  1567.             break;
  1568.         }
  1569.         }
  1570.         }
  1571.     }
  1572.     /* Random values between tot and othertot will have
  1573.        fallen through the loop, and the rslt is NONTTYPE,
  1574.        which indicates that the terrain must be removed
  1575.        if possible. */
  1576.     /* Paranoia check */
  1577.     if (rslt != NONTTYPE && t_subtype(rslt) != t_subtype(t))
  1578.       run_error("badness in damaged_terrain_type");
  1579.     return rslt;
  1580. }
  1581.  
  1582. static void
  1583. notify_combat(unit1, unit2, str)
  1584. Unit *unit1, *unit2;
  1585. char *str;
  1586. {
  1587.     char buf1[BUFSIZE], buf2[BUFSIZE];
  1588.     Side *side3;
  1589.  
  1590.     for_all_sides(side3) {
  1591.     if (active_display(side3)
  1592.         && (all_see_all || side3 == unit1->side || side3 == unit2->side)) {
  1593.         strcpy(buf1, unit_handle(side3, unit1));
  1594.         strcpy(buf2, unit_handle(side3, unit2));
  1595.         notify(side3, str, buf1, buf2);
  1596.     }
  1597.     }
  1598. }
  1599.  
  1600. /* Tests for whether given units or types can do particular types of actions. */
  1601.  
  1602. int
  1603. can_attack(unit)
  1604. Unit *unit;
  1605. {
  1606.     return type_can_attack(unit->type);
  1607. }
  1608.  
  1609. int
  1610. type_can_attack(u)
  1611. int u;
  1612. {
  1613.     int u2;
  1614.     
  1615.     for_all_unit_types(u2) {
  1616.     if (uu_acp_to_attack(u, u2) > 0 && uu_hit(u, u2) > 0 && uu_damage(u, u2) > 0)
  1617.       return TRUE;
  1618.     }
  1619.     return FALSE;
  1620. }
  1621.  
  1622. int
  1623. can_fire(unit)
  1624. Unit *unit;
  1625. {
  1626.     return type_can_fire(unit->type);
  1627. }
  1628.  
  1629. int
  1630. type_can_fire(u)
  1631. int u;
  1632. {
  1633.     int u2, fhit, fdam;
  1634.     
  1635.     if (u_acp_to_fire(u) == 0)
  1636.       return FALSE;
  1637.     for_all_unit_types(u2) {
  1638.     fhit = uu_fire_hit(u, u2);
  1639.     fdam = uu_fire_damage(u, u2);
  1640.     if ((fhit == -1 ? (uu_hit(u, u2) > 0) : (fhit > 0))
  1641.          && (fdam == -1 ? (uu_damage(u, u2) > 0) : (fdam > 0)))
  1642.       return TRUE;
  1643.     }
  1644.     return FALSE;
  1645. }
  1646.  
  1647. int
  1648. type_can_capture(u)
  1649. int u;
  1650. {
  1651.     int u2;
  1652.     
  1653.     for_all_unit_types(u2) {
  1654.     if (uu_acp_to_capture(u, u2) > 0
  1655.         && (uu_capture(u, u2) > 0 || uu_indep_capture(u, u2) > 0))
  1656.       return TRUE;
  1657.     }
  1658.     return FALSE;
  1659. }
  1660.  
  1661. int
  1662. can_detonate(unit)
  1663. Unit *unit;
  1664. {
  1665.     return (u_acp_to_detonate(unit->type) > 0);
  1666. }
  1667.